﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel.Composition;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Anagramme.Contracts;
namespace Anagramme.Model
{
    /// <summary>
    /// Modèle du lobby
    /// </summary>
    [Export(typeof(IService))]
    [Export(typeof(ILobbyModel))]
    [Export(typeof(IDisposable))]
    public sealed class LobbyModel : ModelBase<ILobbyService>, ILobbyModel, ILobbyServiceCallback
    {
        #region ILobbyService Implementation
        /// <summary>
        /// Envoie d'une demande pour changer le mode de jeu
        /// </summary>
        /// <param name="gameMode">Nouveau mode de jeu</param>
        /// <remarks>Nécessite d'être le maitre du lobby</remarks>
        public void RequestLobbyChangeGameMode(GameModes gameMode)
        {
            base.Service.RequestLobbyChangeGameMode(gameMode);
        }

        /// <summary>
        /// Envoie d'une demande pour changer la longueur maximale des mots
        /// </summary>
        /// <param name="length">Nouvelle longueur maximale des mots</param>
        /// <remarks>Nécessite d'être le maitre du lobby</remarks>
        public void RequestLobbyChangeMaxWordsLength(int length)
        {
            base.Service.RequestLobbyChangeMaxWordsLength(length);
        }

        /// <summary>
        /// Envoie d'une demande pour changer la longueur minimale des mots
        /// </summary>
        /// <param name="length">Nouvelle longueur minimale des mots</param>
        /// <remarks>Nécessite d'être le maitre du lobby</remarks>
        public void RequestLobbyChangeMinWordsLength(int length)
        {
            base.Service.RequestLobbyChangeMinWordsLength(length);
        }

        /// <summary>
        /// Envoie d'une demande pour changer le nombre de rounds cible
        /// </summary>
        /// <param name="targetRounds">Nouveau nombre de rounds cible</param>
        /// <remarks>Nécessite d'être le maitre du lobby</remarks>
        public void RequestLobbyChangeTargetRounds(int targetRounds)
        {
            base.Service.RequestLobbyChangeTargetRounds(targetRounds);
        }

        /// <summary>
        /// Envoie d'une demande pour changer le score cible
        /// </summary>
        /// <param name="targetScore">Nouveau score cible</param>
        /// <remarks>Nécessite d'être le maitre du lobby</remarks>
        public void RequestLobbyChangeTargetScore(int targetScore)
        {
            base.Service.RequestLobbyChangeTargetScore(targetScore);
        }

        /// <summary>
        /// Envoie d'une demande d'extinction du serveur
        /// </summary>
        /// <remarks>Nécessite d'être le maitre du lobby</remarks>
        public void RequestLobbyClose()
        {
            base.Service.RequestLobbyClose();
        }

        /// <summary>
        /// Envoie d'une demande pour récupérer les informations sur le serveur
        /// </summary>
        public void RequestLobbyInfos()
        {
            base.Service.RequestLobbyInfos();
        }

        /// <summary>
        /// Indique que le statut "Prêt" à été modifié
        /// </summary>
        /// <param name="isReady">Nouveau statut "Prêt"</param>
        /// <remarks>Vaut True si le joueur est prêt, sinon False</remarks>
        public void RequestLobbyIsReadyToPlay(bool isReady)
        {
            base.Service.RequestLobbyIsReadyToPlay(isReady);
        }

        /// <summary>
        /// Envoie d'une demande pour rejoindre la partie
        /// </summary>
        /// <param name="userName">Nom du joueur</param>
        /// <remarks>Cette méthode est la première à appeler sur le serveur, car elle renvoie le jeton de sécurité nécessaire à tout les autres appels</remarks>
        public void RequestLobbyJoin(string userName)
        {
            base.Service.RequestLobbyJoin(userName);
        }

        /// <summary>
        /// Indique au serveur que le joueur quitte le lobby
        /// </summary>
        public void RequestLobbyLeave()
        {
            base.Service.RequestLobbyLeave();
        }

        /// <summary>
        /// Envoie d'une demande de chargement de la partie
        /// </summary>
        /// <remarks>Cette demande est propagée aux autres joueurs</remarks>
        /// <remarks>Nécessite d'être le maitre du lobby</remarks>
        public void RequestLobbyLoadGame()
        {
            base.Service.RequestLobbyLoadGame();
        }

        /// <summary>
        /// Envoie d'une demande pour récupérer les informations sur le joueur
        /// </summary>
        public void RequestLobbyPlayerInfo()
        {
            base.Service.RequestLobbyPlayerInfo();
        }

        /// <summary>
        /// Envoie d'une demande pour récupérer la liste des joueurs de la partie
        /// </summary>
        public void RequestLobbyPlayers()
        {
            base.Service.RequestLobbyPlayers();
        }
        #endregion

        #region ILobbyModel Implementation
        /// <summary>
        /// Se produit lors du changement de mode de jeu
        /// </summary>
        public event EventHandler<EventArgs<GameModes>> OnResponseLobbyChangeGameMode;

        /// <summary>
        /// Se produit lors du changement de la longueur maximale des mots
        /// </summary>
        public event EventHandler<EventArgs<int>> OnResponseLobbyChangeMaxWordsLength;

        /// <summary>
        /// Se produit lors du changement de la longueur minimale des mots
        /// </summary>
        public event EventHandler<EventArgs<int>> OnResponseLobbyChangeMinWordsLength;

        /// <summary>
        /// Se produit lors du changement du nombre de rounds cible
        /// </summary>
        public event EventHandler<EventArgs<int>> OnResponseLobbyChangeTargetRounds;

        /// <summary>
        /// Se produit lors du changement du score cible
        /// </summary>
        public event EventHandler<EventArgs<int>> OnResponseLobbyChangeTargetScore;

        /// <summary>
        /// Se produit lorsque le serveur est arrêté
        /// </summary>
        public event EventHandler OnResponseLobbyDisconnect;

        /// <summary>
        /// Se produit lors de la récupération des informations sur le lobby
        /// </summary>
        public event EventHandler<EventArgs<LobbyInfo>> OnResponseLobbyInfos;

        /// <summary>
        /// Se produit lors de la connexion au lobby
        /// </summary>
        public event EventHandler<EventArgs<Guid>> OnResponseLobbyJoin;

        /// <summary>
        /// Se produit lors de la notification du serveur du chargement de la partie
        /// </summary>
        public event EventHandler OnResponseLobbyLoadGame;

        /// <summary>
        /// Se produit lors du changement du statut "Prêt" d'un joueur
        /// </summary>
        public event EventHandler<EventArgs<int, bool>> OnResponseLobbyPlayerIsReadyToPlay;

        /// <summary>
        /// Se produit lors de la récupération des informations sur le joueur courrant
        /// </summary>
        public event EventHandler<EventArgs<Player>> OnResponseLobbyPlayerInfo;

        /// <summary>
        /// Se produit lorsqu'un joueur rejoint le lobby
        /// </summary>
        public event EventHandler<EventArgs<Player>> OnResponseLobbyPlayerJoin;

        /// <summary>
        /// Se produit lorsqu'un joueur quitte le lobby
        /// </summary>
        public event EventHandler<EventArgs<int>> OnResponseLobbyPlayerLeave;

        /// <summary>
        /// Se produit lors de la récupération de la liste des joueurs du lobby
        /// </summary>
        public event EventHandler<EventArgs<IEnumerable<Player>>> OnResponseLobbyPlayers;
        #endregion

        #region ILobbyServiceCallback Implementation
        void ILobbyServiceCallback.ResponseLobbyChangeGameMode(GameModes gameMode)
        {
            if (OnResponseLobbyChangeGameMode != null)
                OnResponseLobbyChangeGameMode(this, new EventArgs<GameModes>(gameMode));
        }

        void ILobbyServiceCallback.ResponseLobbyChangeMaxWordsLength(int length)
        {
            if (OnResponseLobbyChangeMaxWordsLength != null)
                OnResponseLobbyChangeMaxWordsLength(this, new EventArgs<int>(length));
        }

        void ILobbyServiceCallback.ResponseLobbyChangeMinWordsLength(int length)
        {
            if (OnResponseLobbyChangeMinWordsLength != null)
                OnResponseLobbyChangeMinWordsLength(this, new EventArgs<int>(length));
        }

        void ILobbyServiceCallback.ResponseLobbyChangeTargetRounds(int targetRounds)
        {
            if (OnResponseLobbyChangeTargetRounds != null)
                OnResponseLobbyChangeTargetRounds(this, new EventArgs<int>(targetRounds));
        }

        void ILobbyServiceCallback.ResponseLobbyChangeTargetScore(int targetScore)
        {
            if (OnResponseLobbyChangeTargetScore != null)
                OnResponseLobbyChangeTargetScore(this, new EventArgs<int>(targetScore));
        }

        void ILobbyServiceCallback.ResponseLobbyDisconnect()
        {
            if (OnResponseLobbyDisconnect != null)
                OnResponseLobbyDisconnect(this, EventArgs.Empty);
        }

        void ILobbyServiceCallback.ResponseLobbyInfos(LobbyInfo infos)
        {
            if (OnResponseLobbyInfos != null)
                OnResponseLobbyInfos(this, new EventArgs<LobbyInfo>(infos));
        }

        void ILobbyServiceCallback.ResponseLobbyJoin(Guid token)
        {
            if (OnResponseLobbyJoin != null)
                OnResponseLobbyJoin(this, new EventArgs<Guid>(token));
        }

        void ILobbyServiceCallback.ResponseLobbyLoadGame()
        {
            if (OnResponseLobbyLoadGame != null)
                OnResponseLobbyLoadGame(this, EventArgs.Empty);
        }

        void ILobbyServiceCallback.ResponseLobbyPlayerInfo(Player player)
        {
            if (OnResponseLobbyPlayerInfo != null)
                OnResponseLobbyPlayerInfo(this, new EventArgs<Player>(player));
        }

        void ILobbyServiceCallback.ResponseLobbyPlayerIsReadyToPlay(int playerId, bool isReadyToPlay)
        {
            if (OnResponseLobbyPlayerIsReadyToPlay != null)
                OnResponseLobbyPlayerIsReadyToPlay(this, new EventArgs<int, bool>(playerId, isReadyToPlay));
        }

        void ILobbyServiceCallback.ResponseLobbyPlayerJoin(Player player)
        {
            if (OnResponseLobbyPlayerJoin != null)
                OnResponseLobbyPlayerJoin(this, new EventArgs<Player>(player));
        }

        void ILobbyServiceCallback.ResponseLobbyPlayerLeave(int playerId)
        {
            if (OnResponseLobbyPlayerLeave != null)
                OnResponseLobbyPlayerLeave(this, new EventArgs<int>(playerId));
        }

        void ILobbyServiceCallback.ResponseLobbyPlayers(IEnumerable<Player> players)
        {
            if (OnResponseLobbyPlayers != null)
                OnResponseLobbyPlayers(this, new EventArgs<IEnumerable<Player>>(players));
        }
        #endregion
    }
}
